Crypto Infinite [crypto]

Crypto Infinite

Crypto has been around forever. Does this challenge go on forever? Let us know in the comments below or find the flag to prove us wrong.

nc chal.tuctf.com 30102

Recon

from pwn import *
import sys

c = remote("chal.tuctf.com", 30102)

while True:
    r = c.readuntil("\n")

    if "Give me text:" in r:
        c.send("abcdefghijklmnopqrstuvwxyz\n")

    if "encrypted is" in r:
        alpha = r.strip("\n").split(" ")[3:]
        print "NEW ALPHA: " + repr(alpha)

    if not r.startswith("Decrypt"):
        print r
        continue

    print "LINE: " + r
    p = r.strip("\n")[8:].split(" ")

    o = ""
    for v in p:
        o += chr(0x41 + alpha.index(v))

    print "GOT: " + o

    c.send(o + "\n")

c.interactive()

L7 solution, breaks on L8

Level 5 is a polyalphabetic substitution for which every character has 8 different encodings, and they are chosen based on pos % 8 of the character in the plaintext. Level 6 introduces a permutation, based on some formula which is based on the length of the plaintext. Level 7 is nothing new...

from pwn import *
import sys

def permute(n):
    perm = {}
    rev = {}
    perm[0], rev[0] = 0, 0
    perm[1], rev[4] = 4, 1
    start = 1

    for i in range(2, n):
        if perm[i-1] + 4 >= n:
            perm[i] = start
            rev[start] = i
            start += 1
        else:
            perm[i] = perm[i-1] + 4
            rev[perm[i]] = i
    def p(s):
        x = list(s)
        for i, v in enumerate(s):
            x[perm[i]] = s[i]
        return x
    def r(s):
        x = list(s)
        for i, v in enumerate(s):
            x[rev[i]] = s[i]
        return x
    return p, r

def buildmap(alpha, encoded, n):
    maps = {}
    for i in range(0, n * int(len(alpha) // n), n):
        for j in range(i, i+n):
            key = (i + j) % n
            if key not in maps:
                maps[key] = {}
            maps[key][encoded[j]] = alpha[j]
    return maps


c = remote("chal.tuctf.com", 30102)

ABC = "abcdefghijklmnopqrstuvwxyz".upper()
alpha = ABC
levels = {
        0: (1, False),
        1: (1, False),
        2: (1, False),
        3: (1, False),
        4: (1, False),
        5: (8, False),
        6: (1, True),
        7: (1, False),
        8: (1, False),
}
level = 0
while True:
    r = c.readuntil("\n")

    if r.startswith("Level"):
        level = int(r.strip("\n").split(" ")[1])

    lrep, permute = levels[level]
    alpha = ''.join([str(i) * lrep for i in ABC])

    if "Give me text:" in r:
        c.send(alpha + "\n")

    if "encrypted is" in r:
        salpha = r.strip("\n").split(" ")[3:]
        if permute:
            salpha = permute(len(salpha))[0](salpha)
        maps = buildmap(alpha, salpha, lrep)
        print("LENGTHS: " + str(len(alpha)) + " " + str(len(salpha)))
        print("ORIG: " + repr(alpha))
        print("NEW ALPHA: " + repr(salpha))

    if not r.startswith("Decrypt"):
        print('< ' + r)
        continue

    print("LINE: " + r)
    p = r.strip("\n")[8:].split(" ")

    o = ""
    for i, v in enumerate(p):
        o += maps[(i % lrep)][v]

    if permute:
        o = ''.join(permute(len(o))[0](o))
    print("GOT: " + repr(o))

    c.send(o + "\n")

c.interactive()

Level 6 samples

A   A   A   A
_|  _|  _|  _|

 B   B   B   B
|_| |_| |_| |_|


A  B   C   D   A  B  C  D
_| _| |_| |_| |_ |_  ]  ]

X  B   U   I   X  B  U  I
.> .> |_| |_|  <  <  |- |-

Y  B   V   J   Y  B  V  J
.< .< |_| |_|  ^  ^ ._| ._|

Y  B   X   J   Y  B  X  J
.< .< |_| |_|  .> .> ._| ._|

Y  B   Y   B   Y  B  Y   B
.< .< |_| |_| .< .< |_| |_|

A  R
_| |.-

R   A
|.- _|

A   R   R  A
_| |.- |.- _|

A  R  R  A   A   R   R   A   A   R   R   A  A  R  R  A
_| _| _| _| |.- |.- |.- |.- |.- |.- |.- |.- _| _| _| _|

A  R  A  R   A   R   A   R  A  R  A  R   A   R   A   R
_| _| _| _| |.- |.- |.- |.- _| _| _| _| |.- |.- |.- |.-

C   R  C  R  C   R   C   R   C  R  C  R  C   R   C   R
|_ |_ |_ |_ |.- |.- |.- |.- |_ |_ |_ |_ |.- |.- |.- |.-


Y  R   Y  R  Y   R   Y   R   Y  R  Y  R  Y   R   Y   R
.< .< .< .< |.- |.- |.- |.- .< .< .< .< |.- |.- |.- |.-

Y   B  Y  B  Y   B   Y   B   Y  B  Y  B  Y   B   Y   B
.< .< .< .< |_| |_| |_| |_| .< .< .< .< |_| |_| |_| |_|

Y   B  Y  B  Y  B   Y   B   Y   B   Y  B  Y  B  Y  B   Y   B   Y   B
.< .< .< .< .< |_| |_| |_| |_| |_| .< .< .< .< .< |_| |_| |_| |_| |_|

Y   Y  Y  Y   Y   B  B   B   B  B   Y  Y  Y  Y   Y   B  B   B  B   B
.< .< |_| .< |_| .< |_| |_| .< |_| .< |_| .< .< |_| .< |_| .< |_| |_|
Y Y B Y B Y B B Y B Y B Y Y B Y B Y B B


 B  A  R  R   A  C  U  D  A
|_| _| _| _| |_ |.- < |.- ]



 B  X  R  A  T   M O  A
|_| > .> .] |.- [. _| _|


 B  X R  A   T   M O   P
|_| > .> .] |.- [. _| .-|


 B  Y R  A   T   M O   P
|_| > .< .] |.- [. _| .-|


 B  S R A   T   M O   P
|_| > v .] |.- [. _| .-|

 B   S   R A   Q   M O   P
|_| |.-| v .] |.- [. _| .-|

 B   S   R T   Q   M O   P
|_| |.-| v .] |.- [. > .-|



A = _|
B = |_|
S = v
R = |.-
P = .-|
T = >
X = .>
C = |_
M = .]

A   B   S   R    P   T  X     C
A   P   B   T    S   X  R     C
_| |_|  v  |.-  .-|  >  .>   |_      # MAPPED 1-1
_| .-| |_|  >    v  .>  |.-  |_      # PERMUTED


0 -> 0
1 -> 2
2 -> 4
3 -> 6
4 -> 1
5 -> 3
6 -> 5
7 -> 7

* 2 then mod 7 for everything between beginning and end for anything larger than 3? Try with length == 9


0   1   2   3    4   5  6     7   8
A   B   S   R    P   T  X     C   X
_| |_|  v  |.-  .-|  >  .>   |_   .>   # MAPPED 1-1
_| .-|  .> |_|   >   v  .>   |.-  |_   # PERMUTED


0 -> 0
1 -> 3
2 -> 5
3 -> 7
4 -> 1
5 -> 4
6 -> 6
7 -> 8
8 -> 2

Unsure of this one, try with M instead of X at the end:

0   1   2   3    4   5  6     7   8
A   B   S   R    P   T  X     C   M
A   P   M   B    T   S  X     R   C    # PERMUTED
_| |_|  v  |.-  .-|  >  .>   |_   .]   # MAPPED 1-1
_| .-|  .] |_|   >   v  .>   |.-  |_   # PERMUTED

0 -> 0
1 -> 3
2 -> 5
3 -> 7
4 -> 1
5 -> 4
6 -> 6
7 -> 8
8 -> 2


0   1   2   3    4
A   B   S   R    P
_| |_|  v  |.- .-|     # MAPPED 1-1
_| .-| |_|  v  |.-     # PERMUTED

0 -> 0
1 -> 2
2 -> 3
3 -> 4
4 -> 1


0   1   2   3    4   5
A   B   S   R    P   T
_| |_|  v  |.- .-|   >     # MAPPED 1-1
_| .-| |_|  >   v   |.-    # PERMUTED


0 -> 0
1 -> 2
2 -> 4
3 -> 5
4 -> 1
5 -> 3

Looks like a permutation (on the indices), for strings of length \(n\) that works as: \(f(0) = 0\) \(f(x) = f(x - 1) + 2 \mod n\) if \(f(x - 1) + 2 \mod n\) has not yet been taken, else keep going by adding 1.

Maybe not..

Okay, permutations are the other way around:

A = _|
B = |_|
S = v
R = |.-
P = .-|
T = >
X = .>
C = |_
M = .]
Z = .^

0   1   2   3    4   5
A   B   S   R    P   T
A   P   B   T    S   R
_| |_|  v  |.- .-|   >     # MAPPED 1-1
_| .-| |_|  >   v   |.-    # PERMUTED


0 -> 0
1 -> 2
2 -> 4
3 -> 5
4 -> 1
5 -> 3

0 -> 0
1 -> 4
2 -> 1
3 -> 5
4 -> 2
5 -> 3

0   1   2   3    4   5  6     7   8   9
A   B   S   R    P   T  X     C   M   Z
A   P   M   B    T   Z  S     X   R   C
_| |_|  v  |.-  .-|  >  .>   |_   .]  .^   # MAPPED 1-1
_| .-|  .] |_|   >   .^ v    .>  |.-  |_  # PERMUTED

0 -> 0
1 -> 3
2 -> 6
3 -> 8
4 -> 1
5 -> 4
6 -> 7
7 -> 9
8 -> 2
9 -> 5

0 -> 0
1 -> 4
2 -> 8
3 -> 1
4 -> 5
5 -> 9
6 -> 2
7 -> 6
8 -> 3
9 -> 7

FINAL SOLUTION

from pwn import *
import sys

def permute(n):
    perm = {}
    rev = {}
    perm[0], rev[0] = 0, 0
    perm[1], rev[4] = 4, 1
    start = 1

    for i in range(2, n):
        if perm[i-1] + 4 >= n:
            perm[i] = start
            rev[start] = i
            start += 1
        else:
            perm[i] = perm[i-1] + 4
            rev[perm[i]] = i
    def p(s):
        x = list(s)
        for i, v in enumerate(s):
            x[perm[i]] = s[i]
        return x
    def r(s):
        x = list(s)
        for i, v in enumerate(s):
            x[rev[i]] = s[i]
        return x
    return p, r

def buildmap(alpha, encoded, n):
    maps = {}
    for i in range(0, n * int(len(alpha) // n), n):
        for j in range(i, i+n):
            key = (i + j) % n
            if key not in maps:
                maps[key] = {}
            maps[key][encoded[j]] = alpha[j]
    return maps


c = remote("chal.tuctf.com", 30102)

ABC = "abcdefghijklmnopqrstuvwxyz".upper()
alpha = ABC
levels = {
        0: (1, False),
        1: (1, False),
        2: (1, False),
        3: (1, False),
        4: (1, False),
        5: (8, False),
        6: (1, True),
        7: (1, False),
        8: (7, False),
        9: (1, True)
}
level = 0
while True:
    r = c.readuntil("\n")

    if r.startswith("Level"):
        level = int(r.strip("\n").split(" ")[1])

    lrep, permute = levels[level]
    alpha = ''.join([str(i) * lrep for i in ABC])
    #if level == 9:
    #    alpha = 'AB' * 8 

    if "Give me text:" in r:
        c.send(alpha + "\n")

    if "encrypted is" in r:
        salpha = r.strip("\n").split(" ")[3:]
        if permute:
            salpha = permute(len(salpha))[0](salpha)
        maps = buildmap(alpha, salpha, lrep)
        print("LENGTHS: " + str(len(alpha)) + " " + str(len(salpha)))
        print("ORIG: " + repr(alpha))
        print("NEW ALPHA: " + repr(salpha))

    if not r.startswith("Decrypt"):
        print('< ' + r)
        continue

    print("LINE: " + r)
    p = r.strip("\n")[8:].split(" ")

    o = ""
    for i, v in enumerate(p):
        o += maps[(i % lrep)][v]

    if permute:
        o = ''.join(permute(len(o))[0](o))
    print("GOT: " + repr(o))

    c.send(o + "\n")

c.interactive()